import { actionManager } from "@/action/ActionManager";
import { CreatePropertyModelTreeSelect } from "@/modules/model/actions/project/CreatePropertyModelTreeSelect";
import { modelService } from "@/modules/model/service";
import { BusEvent } from "@/mdesign-lib/mdesign-app.umd.js";
import { propertyUtil } from "../PropertyUtil";
import { ClassifierData, CreateSpecification, InstanceSlotData, DeleteSlotSpecificationDto } from "../types";
import { PaneModel } from "./PaneModel";
import TextEditor from "@/modules/model/comps/station/sider/attribute/propertyEditors/modals/TextEditor.vue";
import { MetaclassType } from "@/constants/MetaclassType";
import { SlotEditKey } from "@/constants/constants";
import { ActionKey } from "@/action/ActionKey";
import { DateAndTimeSettingInSlotWindow } from "@/config/customSystemConfig/customWindows/dateAndTimeSettingInSlotWindow";
import { PropertyDataType } from "@/constants/Enums";

export class SlotsPaneModel extends PaneModel {
  loading = false;
  tableData: ClassifierData[] = []; // 展示数据
  activePropertyId?: string;
  activeSlotValueId?: string;
  specificationKey = SlotEditKey.SlotValue;
  timePropertyIds = ["81641203057053184", "81641210206904064"];

  async loadTable() {
    const { projectId, modelId, modelData } = this.tabsModel.data;
    if (!projectId || !modelId) return;
    if (modelData?.metaclass != MetaclassType.InstanceSpecification) {
      // 判断是否为实例，如果不是清空缓存，并返回。
      this.tableData = [];

      return;
    }
    this.loading = true;
    try {
      const res = await modelService.queryAllClassifier(projectId, modelId);
      const rows = res as ClassifierData[];
      rows.forEach(row => {
        row.isExpand = true;
        row.slots = [];
      });

      await Promise.all(
        rows.map(row => {
          return this.loadSlots(row);
        })
      );
      this.tableData = rows;
      if (this.activeSlotValueId) {
        const value = this.getActiveSlotValue();
        if (!value) {
          this.activeSlotValueId = undefined;
        }
      }
    } finally {
      this.loading = false;
    }
    this.loaded = true;
  }
  async loadDataWhenNotLoad(): Promise<void> {
    if (!this.loaded) {
      await this.loadTable();
    }
  }
  async loadSlots(row: ClassifierData) {
    const slots = await modelService.slotQueryInstanceSlots(this.tabsModel.projectId, this.tabsModel.data.modelId!, row.id);
    row.slots = slots;
  }

  onPropertyRowClick(row: InstanceSlotData) {
    if (this.activePropertyId === row.propertyId) {
      return;
    } else {
      this.activePropertyId = row.propertyId;

      this.activeSlotValueId = row.values[0]?.id;
    }
  }
  onSlotValueClick(propertyId: string, slotValueId: string) {
    this.activeSlotValueId = slotValueId;
    this.activePropertyId = propertyId;
  }
  async handelSpread(row: ClassifierData) {
    row.isExpand = true;
  }

  async handleShrink(row: ClassifierData) {
    row.isExpand = false;
  }

  async handleSpreadAll() {
    this.tableData.forEach(row => {
      row.isExpand = true;
    });
  }
  async handleShrinkAll() {
    this.tableData.forEach(row => {
      row.isExpand = false;
    });
  }

  async addSlotValue(data: InstanceSlotData) {
    if (data.dataType == PropertyDataType.STRING && this.timePropertyIds.includes(data.propertyId)) {
      await DateAndTimeSettingInSlotWindow.popup(
        {
          date: ""
        },
        async ({ success, result }) => {
          if (success) {
            const { date } = result;
            const dto: CreateSpecification = {
              projectId: this.tabsModel.projectId,
              propertyId: data.propertyId!,
              slotId: data.slotId,
              parentId: this.tabsModel.data.modelId!,
              key: this.specificationKey,
              value: date
            };

            await propertyUtil.updatePropertySlotAndFresh(dto);
          }
          DateAndTimeSettingInSlotWindow.done();
        }
      );

      return;
    }

    if (
      data.dataType == PropertyDataType.STRING ||
      data.dataType == PropertyDataType.REAL ||
      data.dataType == PropertyDataType.INTEGER ||
      data.dataType == PropertyDataType.UNLIMITEDNATURAL
    ) {
      let hasError = false;
      const needValidTypes: Array<any> = [PropertyDataType.REAL, PropertyDataType.INTEGER, PropertyDataType.UNLIMITEDNATURAL];
      const realReg = /^[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?$/;
      const integerReg = /^[-+]?\d+$/;

      const newText = await TextEditor.popup({
        title: data.name,
        text: "",
        validText: async (text: string) => {
          if (!needValidTypes.includes(data.dataType)) {
            return true;
          }
          let reg = data.dataType === PropertyDataType.INTEGER ? integerReg : realReg;
          if (!reg.test(text)) {
            await app.$notify({
              type: "error",
              title: "提示",
              message: "类型不匹配"
            });
            return false;
          } else {
            return true;
          }
        }
      }).catch((err: any) => {
        err && console.error(err);
        hasError = true;
      });
      if (hasError) return;

      const dto: CreateSpecification = {
        projectId: this.tabsModel.projectId,
        propertyId: data.propertyId!,
        slotId: data.slotId,
        parentId: this.tabsModel.data.modelId!,
        key: this.specificationKey,
        value: newText
      };

      await propertyUtil.updatePropertySlotAndFresh(dto);
    } else if (data.dataType == PropertyDataType.INSTANCE) {
      const row = {
        ...data,
        checkMethod: "checkSlotValueByProperty",
        projectId: this.tabsModel.projectId,
        key: this.specificationKey,
        modelId: data.propertyId,
        parentId: this.tabsModel.data.modelId,
        isMultiplicity: true
      };
      const action = actionManager.getAction(ActionKey.CreatePropertyModelTreeSelect) as CreatePropertyModelTreeSelect;

      action.createProperty(row, "attrSlots", "插槽");
    } else if (data.dataType == PropertyDataType.BOOLEAN || propertyUtil.isRowDataTypeEnum(data)) {
      await this.addOrUpdateSlotValue(data);
    }
  }
  async addOrUpdateSlotValue(row: InstanceSlotData, valueId?: string, value?: string | boolean) {
    const dto: CreateSpecification = {
      projectId: this.tabsModel.projectId,
      propertyId: row.propertyId!,
      slotId: row.slotId,
      parentId: this.tabsModel.data.modelId,
      value: value || "",
      valueSpecificationId: valueId || "",
      key: this.specificationKey
    };
    await propertyUtil.updatePropertySlotAndFresh(dto);
  }
  getActiveSlotValue() {
    for (let classifier of this.tableData) {
      for (let slot of classifier.slots) {
        for (let value of slot.values) {
          if (value.id === this.activeSlotValueId) {
            return value;
          }
        }
      }
    }
  }
  async deleteSlotValue(data: InstanceSlotData) {
    const slotValue = this.getActiveSlotValue();
    if (!slotValue) {
      return;
    }
    const dto: DeleteSlotSpecificationDto = {
      projectId: this.tabsModel.projectId!,
      specificationId: slotValue.id,
      slotId: data.slotId!
    };

    await propertyUtil.deleteSpecification(dto);
    this.activeSlotValueId = undefined;
  }
  async handleChange() {}
  async editSlotValue(data: InstanceSlotData) {
    const slotValue = this.getActiveSlotValue();
    if (!slotValue) {
      return;
    }
    if (data.dataType == PropertyDataType.STRING && this.timePropertyIds.includes(data.propertyId)) {
      await DateAndTimeSettingInSlotWindow.popup(
        {
          date: slotValue.value as string
        },
        async ({ success, result }) => {
          if (success) {
            const { date } = result;
            const dto: CreateSpecification = {
              projectId: this.tabsModel.projectId!,
              propertyId: data.propertyId!,
              slotId: data.slotId,
              parentId: this.tabsModel.data.modelId!,
              value: date,
              valueSpecificationId: slotValue.id
            };

            const res = await propertyUtil.updatePropertySlotAndFresh(dto);
            if (res) {
              app.$bus.emit(BusEvent.REFRESH_SLOT, this.tabsModel.data.modelId);
            }
          }
          DateAndTimeSettingInSlotWindow.done();
        }
      );

      return;
    }

    let hasError = false;
    const needValidTypes: Array<any> = [PropertyDataType.REAL, PropertyDataType.INTEGER, PropertyDataType.UNLIMITEDNATURAL];
    const realReg = /^[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?$/;
    const integerReg = /^[-+]?\d+$/;

    const newText = await TextEditor.popup({
      title: data.name,
      text: slotValue.value,
      validText: async (text: string) => {
        if (!needValidTypes.includes(data.dataType)) {
          return true;
        }
        let reg = data.dataType === PropertyDataType.INTEGER ? integerReg : realReg;
        if (!reg.test(text)) {
          await app.$notify({
            type: "error",
            title: "提示",
            message: "类型不匹配"
          });
          return false;
        } else {
          return true;
        }
      }
    }).catch((err: any) => {
      err && console.error(err);
      hasError = true;
    });

    if (hasError) return;

    const dto: CreateSpecification = {
      projectId: this.tabsModel.projectId!,
      propertyId: data.propertyId!,
      slotId: data.slotId,
      parentId: this.tabsModel.data.modelId!,

      value: newText || "",
      valueSpecificationId: slotValue.id
    };
    const res = await propertyUtil.updatePropertySlotAndFresh(dto);

    if (res) {
      app.$bus.emit(BusEvent.REFRESH_SLOT, this.tabsModel.data.modelId);
    }
  }

  async fresh() {
    this.loadTable();
  }

  async clear() {
    this.tableData = [];
    this.loaded = false;
  }
}
